from PyQt5 import QtWidgets, uic

from PyQt5.QtCore import QTimer
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from qt_material import apply_stylesheet

from ui_util import *
from work_threads import *
from vision_utils import setloopok

# from decision_util import GameStatus, DecisionUtil

from loguru import logger
import time
import sys
import os

setloopok(True)


class AutoChessWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super(AutoChessWindow, self).__init__()
        uic.loadUi("./main_window.ui", self)

        assert os.path.exists("./az.rknn"), "Please download az.rknn from the repo"
        model = load_rknn_model("./az.rknn")
        self.player = AlphaZeroRKPlayer(model=model, simulations=1000)
        self.status = GameStatus.SYS_INIT

        # labels
        self.timeLab = self.findChild(QLabel, "timeLab")
        self.roundInfoLab = self.findChild(QLabel, "roundInfoLab")
        # buttons
        self.startBut = self.findChild(QPushButton, "startBut")
        self.resetBut = self.findChild(QPushButton, "resetBut")
        self.resetBoardBut = self.findChild(QPushButton, "resetBoardBut")
        self.runTestBut = self.findChild(QPushButton, "runTestBut")
        self.saveSetBut = self.findChild(QPushButton, "saveSetBut")
        self.updateDevBut = self.findChild(QPushButton, "updateDevBut")
        # combo boxes
        self.firstPlayerCob = self.findChild(QComboBox, "firstplayerCob")
        self.userColorCob = self.findChild(QComboBox, "userColorCob")
        self.setTestPickColorCob = self.findChild(QComboBox, "setTestPickColorCob")
        self.setSysSerCob = self.findChild(QComboBox, "setSysSerCob")
        self.setSysCamCob = self.findChild(QComboBox, "setSysCamCob")
        # line edits
        self.setTestPlaceEit = self.findChild(QLineEdit, "setTestPlaceEit")

        self.timer = QTimer()
        self.timer.setInterval(1000)
        self.timerPause = True
        self.timeValue = 0
        self.timer.timeout.connect(self.timerCallback)
        self.timer.start()

        self.gameThread = None
        self.resetBoardThread = None
        self.testThread = None

        self.initCombos()

        self.updateDevBut.clicked.connect(self.updateDevicesEvt)
        self.saveSetBut.clicked.connect(self.saveSettingsEvt)
        self.runTestBut.clicked.connect(self.runTestEvt)
        self.resetBoardBut.clicked.connect(self.resetBoardEvt)
        self.startBut.clicked.connect(self.startGameEvt)
        self.resetBut.clicked.connect(self.resetGameEvt)

    def initCombos(self):
        self.firstPlayerCob.clear()
        self.userColorCob.clear()
        self.setTestPickColorCob.clear()
        self.firstPlayerCob.addItems(["造物", "用户"])
        self.userColorCob.addItems(["黑子", "白子"])
        self.setTestPickColorCob.addItems(["黑子", "白子"])
        self.updateDevicesEvt()

        setting = read_settings()

        self.firstPlayerCob.setCurrentText(setting["first_player"])
        self.userColorCob.setCurrentText(setting["user_color"])
        self.setSysSerCob.setCurrentText(setting["serial_port"])
        self.setSysCamCob.setCurrentText(setting["camera_index"])

        self.firstPlayerCob.currentTextChanged.connect(self.updateInitRoundLab)
        self.updateInitRoundLab()

    def updateInitRoundLab(self):
        self.roundInfoLab.setText(f"{self.firstPlayerCob.currentText()}先手")

    def timerCallback(self):
        if not self.timerPause:
            self.timeValue += 1

        timeStr = f"{self.timeValue // 60:02}:{self.timeValue % 60:02}"
        self.timeLab.setText(timeStr)

    def updateDevicesEvt(self):
        self.setSysSerCob.clear()
        self.setSysCamCob.clear()
        self.setSysSerCob.addItems(get_serial_ports())
        self.setSysCamCob.addItems(get_camera_list())

    def saveSettingsEvt(self):
        settings = {
            "serial_port": self.setSysSerCob.currentText(),
            "camera_index": self.setSysCamCob.currentText(),
            "first_player": self.firstPlayerCob.currentText(),
            "user_color": self.userColorCob.currentText(),
        }
        save_settings(settings)

    def runTestEvt(self):
        if self.runTestBut.text() == "执行":
            targetColor = 0 if self.setTestPickColorCob.currentText() == "黑子" else 1
            targetPlace = self.setTestPlaceEit.text()

            if not (
                len(targetPlace) == 3
                and targetPlace[1] == ","
                and targetPlace[2] in "012"
                and targetPlace[0] in "012"
            ):
                QMessageBox.warning(self, "警告", "请输入有效的格子位置")
                return

            targetPlace = tuple(map(lambda x: int(x), targetPlace.split(",")))

            self.runTestBut.setText("停止")
            self.gameLogic = get_game_logic(
                self.setSysCamCob.currentText(),
                self.setSysSerCob.currentText(),
                GameStatus.SYS_INIT,
                0 if self.userColorCob.currentText() == "黑子" else 1,
                self.player,
            )
            self.runTestThread = TestThread(self.gameLogic, targetColor, targetPlace)
            self.runTestThread.finished.connect(self.finishRunTestEvt)
            self.runTestThread.start()
            logger.info("run test thread started")
        else:
            self.runTestBut.setText("执行")
            setloopok(False)
            self.runTestThread.quit()
            self.runTestThread.wait()

    def finishRunTestEvt(self):
        self.runTestBut.setText("执行")
        self.gameLogic.get_decision().release_driver()
        self.gameLogic = None
        self.runTestThread.deleteLater()
        logger.info("<finishRunTestEvt> run test thread finished")
        setloopok(True)

    def resetBoardEvt(self):
        if self.resetBoardBut.text() == "执行":
            self.resetBoardBut.setText("停止")
            self.gameLogic = get_game_logic(
                self.setSysCamCob.currentText(),
                self.setSysSerCob.currentText(),
                GameStatus.SYS_INIT,
                0 if self.userColorCob.currentText() == "黑子" else 1,
                self.player,
            )
            self.resetBoardThread = ResetBoardThread(self.gameLogic)
            self.resetBoardThread.finished.connect(self.finishResetBoardEvt)

            self.resetBoardThread.start()
            logger.info("reset board thread started")
        else:
            self.resetBoardBut.setText("执行")
            setloopok(False)
            self.resetBoardThread.quit()
            self.resetBoardThread.wait()

    def finishResetBoardEvt(self):
        self.resetBoardBut.setText("执行")
        self.gameLogic.get_decision().release_driver()
        self.gameLogic = None
        self.resetBoardThread.deleteLater()
        logger.info("<finishResetBoardEvt> reset board thread finished")
        self.resetBoardBut.setEnabled(True)
        setloopok(True)

    def startGameEvt(self):
        if self.status == GameStatus.USER_ACT:
            self.gameLogic.user_acting_done()
            self.startBut.setEnabled(False)
            self.startBut.setText("开始")
            return

        self.gameLogic = get_game_logic(
            self.setSysCamCob.currentText(),
            self.setSysSerCob.currentText(),
            (
                GameStatus.USER_ACT
                if self.firstPlayerCob.currentText() == "用户"
                else GameStatus.BOT_ACT
            ),
            0 if self.userColorCob.currentText() == "黑子" else 1,
            self.player,
        )
        self.gameThread = GameThread(self.gameLogic)
        self.gameThread.status_trigger.connect(self.gameStatusHandler)
        self.gameThread.finished.connect(self.finishStartGameEvt)
        self.gameThread.start()

        self.startBut.setEnabled(False)
        self.runTestBut.setEnabled(False)
        self.resetBoardBut.setEnabled(False)

        self.timerPause = False
        logger.info("Start game")

    def finishStartGameEvt(self):
        self.startBut.setEnabled(True)
        self.runTestBut.setEnabled(True)
        self.resetBoardBut.setEnabled(True)
        self.updateInitRoundLab()

        self.timerPause = True
        self.timeValue = 0
        self.timerCallback()

        self.gameLogic.get_decision().release_driver()
        self.gameLogic = None
        self.gameThread.deleteLater()
        logger.info("<finishStartGameEvt> reset board thread finished")
        setloopok(True)

    def gameStatusHandler(self, gamestatus):
        self.status = gamestatus
        logger.info("<gameStatusHandler> game status: {}", gamestatus)

        if gamestatus == GameStatus.USER_ACT:
            self.roundInfoLab.setText("用户行动")
            self.startBut.setText("完成")
            self.startBut.setEnabled(True)
            self.timeValue = 0
            self.timerCallback()
        elif gamestatus == GameStatus.BOT_ACT:
            self.roundInfoLab.setText("造物行动")
            self.timeValue = 0
            self.timerCallback()
        elif gamestatus == GameStatus.ANTI_CHEAT:
            self.roundInfoLab.setText("反作弊")
            self.timeValue = 0
            self.timerCallback()
        elif gamestatus == GameStatus.GAME_OVER:
            self.updateInitRoundLab()
            self.timerPause = True
            self.timeValue = 0
            self.timerCallback()
            QMessageBox.information(self, "游戏结束", "游戏结束")
        elif gamestatus == GameStatus.INIT:
            self.roundInfoLab.setText("初始化")

    def resetGameEvt(self):
        if self.gameThread is not None:
            try:
                if self.gameThread.isRunning():
                    setloopok(False)
                    self.gameThread.quit()
                    self.gameThread.wait()
                    return
            except Exception as e:
                logger.error(traceback.format_exc())

        self.startBut.setEnabled(True)
        self.runTestBut.setEnabled(True)
        self.resetBoardBut.setEnabled(True)
        self.updateInitRoundLab()

        self.timerPause = True
        self.timeValue = 0
        self.timerCallback()

        self.status = GameStatus.SYS_INIT
        self.startBut.setText("开始")


if __name__ == "__main__":
    # create the application and the main window
    app = QtWidgets.QApplication(sys.argv)
    window = AutoChessWindow()

    # setup stylesheet
    # apply_stylesheet(app, theme="light_blue.xml", extra={"font_family": "Roboto"})

    # run
    window.show()
    app.exec_()
